package syM

import (
	"bytes"
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"db2s/Er"
	"db2s/Meta"
	ea "db2s/encryptionAlgorithm"
	"db2s/global"
	"db2s/go-log/log"
	"db2s/outPut"
	"db2s/parDef"
	mq "db2s/topic-mq"
	"reflect"
	"strings"
	"sync/atomic"
)

func errorActive(_ int64, plan *SchedulePlan2, err string) (errStr string) {
	if strings.EqualFold(err, "column length abnormal") { //表结构不一致
		var srcColumn, dstColumn []string
		var returnError bytes.Buffer
		for _, v := range plan.tableColData.SColumnInfo {
			srcColumn = append(srcColumn, v["columnName"])
		}
		for _, v := range plan.tableColData.DColumnInfo {
			dstColumn = append(dstColumn, v["columnName"])
		}
		aa := &ea.CheckSumTypeStruct{}
		add, del := aa.Arrcmp(srcColumn, dstColumn)
		for _, v := range add {
			returnError.WriteString(fmt.Sprintf("add column %v ,", v))
		}
		for _, v := range del {
			returnError.WriteString(fmt.Sprintf("drop column %v,", v))
		}
		errStr = returnError.String()
		returnError.Reset()
	} else {
		errStr = err
	}
	return
}

// 出现错误集体处理
func (sp SchedulePlan2) errorAction(logSeq int64, err any) {
	atomic.SwapInt64(sp.Status.ErrEnd, -1)
	if PlanContext.TaskBarSubsStatusGet(sp.subTaskInfo) != -2 {
		PlanContext.TaskBarSubsStatusSwap(sp.subTaskInfo, "error")
	}
	atomic.SwapInt64(sp.MQ.ErrStatus, -1)
	PlanContext.TaskBarSubsErrorSwap(sp.subTaskInfo, errorActive(logSeq, &sp, fmt.Sprintf("%v", err)))
}

func GetTableExist(plan *SchedulePlan2) (exist bool, err error) {
	c := Meta.NewMeta([]string{GlobalPConfigs.dSns.SrcDBName, GlobalPConfigs.dSns.DestDBName}, "right", plan.Object.Role)
	c.Parameter1 = append(c.Parameter1, parDef.Parameter{Con: GlobalPConfigs.db.Source.GetDB("single"), Object: parDef.Object{Schema: plan.Object.Schema, Table: plan.Object.Table}})
	c.Parameter1 = append(c.Parameter1, parDef.Parameter{Con: GlobalPConfigs.db.Target.GetDB("single"), Object: parDef.Object{Schema: plan.Object.MSchema, Table: plan.Object.MTable}})
	if exist, err = c.GetObjectExistence(); err != nil {
		return
	}
	return
}
func (sp *SchedulePlan2) GetTableRecordMeta(db map[string]*sql.DB, dbDrive, drive string, logSeq int64) (comment global.TableRecordMeta, err error) {
	var (
		schema, table string
		f1            global.TableCommentReturnResult
		event         = "[GetTableRecordMeta]"
		o             Er.TablesMetaInfoEr
	)
	if o, err = Er.MetaInfo(Er.TableInfoMeta{
		DBType: dbDrive,
	}); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("%v Get the table wildcard %v under the specified schema %v failed. error is %v", event, table, schema, err))
		return
	}
	switch drive {
	case "source":
		schema = sp.Object.Schema
		table = sp.Object.Table
	case "dest":
		schema = sp.Object.MSchema
		table = sp.Object.MTable
	}
	if f1, err = o.Comment(global.TablesMetaInfoInput{
		LogSeq: logSeq,
		DB:     db,
		TableInfo: global.TableInfo{
			Schema: schema,
			Table:  table,
		},
		Input: sp.Object.Input,
	}); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("(%v) %v get %v table %v.%v comment fail. error is %v", sp.Object.ObjectLogSeq, event, drive, sp.Object.Schema, sp.Object.Table, err))
		return
	}
	comment = f1.Result
	return
}
func (sp *SchedulePlan2) GetTableColumn(db map[string]*sql.DB, dbDrive, drive string, logSeq int64) ([]global.TableMeta, error) {
	var (
		columnGarth   any
		schema, table string
		event         = "[getTableColumn]"
		p             Er.TableColumnEr
		err           error
	)
	if p, err = Er.ColumnData(Er.TableColumn{
		DBType: dbDrive,
	}); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("%v Get the table wildcard %v under the specified schema %v failed. error is %v", event, table, schema, err))
		return nil, err
	}
	switch drive {
	case "source":
		schema = sp.Object.Schema
		table = sp.Object.Table
	case "dest":
		schema = sp.Object.MSchema
		table = sp.Object.MTable
	}
	if columnGarth, err = p.All(global.GetColumnTypeInput{
		LogSeq: logSeq,
		DB:     db,
		TableInfo: global.TableInfo{
			Schema: schema,
			Table:  table,
		}}); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("(%v) %v get %v table %v.%v column metadata fail. error is %v", sp.Object.ObjectLogSeq, event, drive, sp.Object.Schema, sp.Object.Table, err))
		return nil, err
	}
	return columnGarth.(global.AllReturnResult).Result, nil
}
func (sp *SchedulePlan2) GetTableIndex(db map[string]*sql.DB, dbDrive, drive string, logSeq int64) (global.IndexMerge, error) {
	var (
		indexGarth    global.IndexMerge
		schema, table string
		event         = "[GetTableIndex]"
		result        any
		o             Er.TablesMetaInfoEr
		err           error
	)
	if o, err = Er.MetaInfo(Er.TableInfoMeta{
		DBType: dbDrive,
	}); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("%v Get the table wildcard %v under the specified schema %v failed. error is %v", event, table, schema, err))
		return global.IndexMerge{}, err
	}
	switch drive {
	case "source":
		schema = sp.Object.Schema
		table = sp.Object.Table
	case "dest":
		schema = sp.Object.MSchema
		table = sp.Object.MTable
	}
	if result, err = o.IndexColumn(global.TablesMetaInfoInput{
		LogSeq: logSeq,
		DB:     db,
		TableInfo: global.TableInfo{
			Schema: schema,
			Table:  table,
		},
	}); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("(%v) %v get %v table %v.%v index metadata fail. error is %v", sp.Object.ObjectLogSeq, event, drive, sp.Object.Schema, sp.Object.Table, err))
		return indexGarth, err
	} else {
		switch fmt.Sprintf("%v", reflect.TypeOf(result)) {
		case "[]global.IndexColumn":
			if result != nil {
				indexGarth = o.IndexMerge(global.TablesMetaInfoInput{
					LogSeq:      logSeq,
					IndexColumn: result.([]global.IndexColumn),
				})
			}
		}
	}
	return indexGarth, nil
}

func (sp *SchedulePlan2) GetTablePartition(db map[string]*sql.DB, dbDrive, drive string, logSeq int64) ([]global.TablePartitionConfig, error) {
	var (
		err            error
		partitionGarth any
		schema, table  string
		event          = "[GetTablePartition]"
		o              Er.TablesMetaInfoEr
	)
	switch drive {
	case "source":
		schema = sp.Object.Schema
		table = sp.Object.Table
	case "dest":
		schema = sp.Object.MSchema
		table = sp.Object.MTable
	}
	if o, err = Er.MetaInfo(Er.TableInfoMeta{
		DBType: dbDrive,
	}); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("%v Get the table wildcard %v under the specified schema %v failed. error is %v", event, table, schema, err))
		return nil, err
	}
	//p := tableEr.MetaInfo(tableEr.TableInfoMeta{DBType: dbDrive})
	if partitionGarth, err = o.PartitionConfig(global.TablesMetaInfoInput{
		LogSeq: logSeq,
		DB:     db,
		TableInfo: global.TableInfo{
			Schema: schema,
			Table:  table,
		},
	}); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("(%v) %v get %v table %v.%v partition metadata fail. error is %v", sp.Object.ObjectLogSeq, event, drive, sp.Object.Schema, sp.Object.Table, err))
		return []global.TablePartitionConfig{}, err
	}
	if partitionGarth == nil {
		return []global.TablePartitionConfig{}, nil
	}
	return partitionGarth.([]global.TablePartitionConfig), nil
}
func (sp *SchedulePlan2) TableMetaAbnormalComparison(h map[string][]global.TableMeta) *global.MetaModifyAttributesAb {
	var (
		funcM = map[string]reflect.Value{
			"type":      reflect.ValueOf(sp.TableColumnType),
			"null":      reflect.ValueOf(sp.TableColumnNull),
			"default":   reflect.ValueOf(sp.TableColumnDefault),
			"comment":   reflect.ValueOf(sp.TableColumnComment),
			"charset":   reflect.ValueOf(sp.TableColumnCharset),
			"collation": reflect.ValueOf(sp.TableColumnCollation),
		}
		nameDiff         any
		eq               []string
		modifyAttributes = &global.MetaModifyAttributesAb{}
	)
	s, ok1 := h["source"]
	d, ok2 := h["dest"]
	if !ok1 || !ok2 {
		return modifyAttributes
	}
	nameDiff = sp.TableColumnName(s, d)
	switch fmt.Sprintf("%v", reflect.TypeOf(nameDiff)) {
	case "map[string][]string":
		if a, ok := nameDiff.(map[string][]string)["add"]; ok {
			modifyAttributes.Add = a
		}
		if a, ok := nameDiff.(map[string][]string)["del"]; ok {
			modifyAttributes.Del = a
		}
		if a, ok := nameDiff.(map[string][]string)["eq"]; ok {
			eq = a
		}
		var a = make(map[string]*global.MetaAttributesAb)
		for _, v := range eq {
			a[v] = &global.MetaAttributesAb{}
		}
		modifyAttributes.Mod = a
	}
	for k, v := range funcM {
		var activeTrue bool
		if strings.Contains(strings.ToLower(strings.Join(GlobalPConfigs.structs.AlterSubObject["column"], ",")), k) {
			activeTrue = true
		}
		if !activeTrue {
			continue
		}
		args := []reflect.Value{
			reflect.ValueOf(eq),
			reflect.ValueOf(s),
			reflect.ValueOf(d),
		}
		p := v.Call(args)[0].Interface()
		switch fmt.Sprintf("%v", reflect.TypeOf(p)) {
		case "[]string":
			switch k {
			case "type":
				for _, x := range p.([]string) {
					if y, z := modifyAttributes.Mod[x]; z {
						y.Type = true
					}
				}
			case "null":
				for _, x := range p.([]string) {
					if y, z := modifyAttributes.Mod[x]; z {
						y.Null = true
					}
				}
			case "default":
				for _, x := range p.([]string) {
					if y, z := modifyAttributes.Mod[x]; z {
						y.Default = true
					}
				}
			case "comment":
				for _, x := range p.([]string) {
					if y, z := modifyAttributes.Mod[x]; z {
						y.Comment = true
					}
				}
			case "charset":
				for _, x := range p.([]string) {
					if y, z := modifyAttributes.Mod[x]; z {
						y.Charset = true
					}
				}
			case "collation":
				for _, x := range p.([]string) {
					if y, z := modifyAttributes.Mod[x]; z {
						y.Collation = true
					}
				}
			}
		}
	}
	return modifyAttributes
}
func (sp *SchedulePlan2) TableIndexAbnormalComparison(h map[string]global.IndexMerge) *global.IndexModifyAttributesAb {
	var (
		nameDiff         any
		eq               []string
		modifyAttributes = &global.IndexModifyAttributesAb{}
	)
	s, ok1 := h["source"]
	d, ok2 := h["dest"]
	if !ok1 && !ok2 {
		return modifyAttributes
	}
	nameDiff = sp.TableIndexName(s, d)
	switch fmt.Sprintf("%v", reflect.TypeOf(nameDiff)) {
	case "map[string][]string":
		if a, ok := nameDiff.(map[string][]string)["add"]; ok {
			modifyAttributes.Add = a
		}
		if a, ok := nameDiff.(map[string][]string)["del"]; ok {
			modifyAttributes.Del = a
		}
		if a, ok := nameDiff.(map[string][]string)["eq"]; ok {
			eq = a
		}
		var a = make(map[string]*global.IndexAttributesAb)
		for _, v := range eq {
			f := &global.IndexAttributesAb{}
			if !strings.EqualFold(s.IndexType[v], d.IndexType[v]) {
				f.Type = true
			}
			var e, g []string
			for _, j := range s.IndexColumn[v] {
				e = append(e, j.ColumnName)
			}
			for _, j := range d.IndexColumn[v] {
				g = append(g, j.ColumnName)
			}
			if !strings.EqualFold(strings.Join(e, ","), strings.Join(g, ",")) {
				f.ColumnName = true
			}
			a[v] = f
		}
		modifyAttributes.Mod = a
	}
	return modifyAttributes
}
func (sp *SchedulePlan2) TablePartitionAbnormalComparison(h map[string][]global.TablePartitionConfig) *global.PartitionModifyAttributesAb {
	var (
		nameDiff         any
		eq               []string
		modifyAttributes = &global.PartitionModifyAttributesAb{}
	)
	s, ok1 := h["source"]
	d, ok2 := h["dest"]
	if !ok1 && !ok2 {
		return modifyAttributes
	}
	nameDiff = sp.TablePartitionName(s, d)
	switch fmt.Sprintf("%v", reflect.TypeOf(nameDiff)) {
	case "map[string][]string":
		if a, ok := nameDiff.(map[string][]string)["add"]; ok {
			modifyAttributes.Add = a
		}
		if a, ok := nameDiff.(map[string][]string)["del"]; ok {
			modifyAttributes.Del = a
		}
		if a, ok := nameDiff.(map[string][]string)["eq"]; ok {
			eq = a
		}
		var a []string
		for _, v := range eq {
			var src, dst global.TablePartitionConfig
			for _, c := range s {
				if strings.EqualFold(v, c.FirstPartition.Name) {
					src = c
				}
			}
			for _, c := range d {
				if strings.EqualFold(v, c.FirstPartition.Name) {
					dst = c
				}
			}
			if !strings.EqualFold(src.FirstPartition.Rules, dst.FirstPartition.Rules) {
				a = append(a, v)
			}
		}
		modifyAttributes.Mod = a
	}
	return modifyAttributes
}

func (sp *SchedulePlan2) TableColumnName(s, d any) any {
	var (
		aa                = &ea.CheckSumTypeStruct{}
		c                 = make([][]string, 2)
		union, Complement = make(map[string]int), make(map[string]int)
	)
	for k, v := range []any{s, d} {
		switch fmt.Sprintf("%v", reflect.TypeOf(v)) {
		case "[]global.TableMeta":
			var x []string
			for _, w := range v.([]global.TableMeta) {
				if GlobalPConfigs.rules.Struct.Case {
					x = append(x, w.ColumnName)
					union[w.ColumnName]++
				} else {
					x = append(x, strings.ToUpper(w.ColumnName))
					union[strings.ToUpper(w.ColumnName)]++
				}
			}
			c[k] = x
		}
	}
	add, del := aa.Arrcmp(c[0], c[1])
	var eq []string
	for _, v := range [][]string{
		add, del,
	} {
		for _, w := range v {
			Complement[w]++
		}
	}
	for k := range union {
		if _, ok := Complement[k]; !ok {
			eq = append(eq, k)
		}
	}
	return map[string][]string{"add": add, "del": del, "eq": eq}
}

func (sp *SchedulePlan2) TableIndexName(s, d any) any {
	var (
		aa                = &ea.CheckSumTypeStruct{}
		c                 = make([][]string, 2)
		union, Complement = make(map[string]int), make(map[string]int)
	)
	for k, v := range []any{s, d} {
		switch fmt.Sprintf("%v", reflect.TypeOf(v)) {
		case "global.IndexMerge":
			var x []string
			for y := range v.(global.IndexMerge).IndexColumn {
				x = append(x, y)
				union[y]++
			}
			c[k] = x
		}
	}
	add, del := aa.Arrcmp(c[0], c[1])
	var eq []string
	for _, v := range [][]string{
		add, del,
	} {
		for _, w := range v {
			Complement[w]++
		}
	}
	for k := range union {
		if _, ok := Complement[k]; !ok {
			eq = append(eq, k)
		}
	}
	return map[string][]string{"add": add, "del": del, "eq": eq}
}
func (sp *SchedulePlan2) TablePartitionName(s, d any) any {
	var (
		aa                = &ea.CheckSumTypeStruct{}
		c                 = make([][]string, 2)
		union, Complement = make(map[string]int), make(map[string]int)
	)
	for k, v := range []any{s, d} {
		switch fmt.Sprintf("%v", reflect.TypeOf(v)) {
		case "[]global.TablePartitionConfig":
			var x []string
			for _, y := range v.([]global.TablePartitionConfig) {
				x = append(x, y.FirstPartition.Name)
				union[y.FirstPartition.Name]++
			}
			c[k] = x
		}
	}
	add, del := aa.Arrcmp(c[0], c[1])
	var eq []string
	for _, v := range [][]string{
		add, del,
	} {
		for _, w := range v {
			Complement[w]++
		}
	}
	for k := range union {
		if _, ok := Complement[k]; !ok {
			eq = append(eq, k)
		}
	}
	return map[string][]string{"add": add, "del": del, "eq": eq}
}
func (sp *SchedulePlan2) TableColumnType(eq []string, s, d any) any {
	var (
		union  []map[string]global.ConvertColumnMeta
		modify []string
	)
	for _, v := range []any{s, d} {
		switch fmt.Sprintf("%v", reflect.TypeOf(v)) {
		case "[]global.TableMeta":
			var x = make(map[string]global.ConvertColumnMeta)
			for _, w := range v.([]global.TableMeta) {
				var columnName = w.ColumnName
				if !GlobalPConfigs.rules.Struct.Case {
					columnName = strings.ToUpper(w.ColumnName)
				}
				x[columnName] = w.ConvertColumnType
			}
			union = append(union, x)
		}
	}
	for _, u := range eq {
		var columnCover []global.ConvertColumnMeta
		for _, v := range union {
			if w, ok := v[u]; ok {
				columnCover = append(columnCover, w)
			}
		}
		source, dest := columnCover[0], columnCover[1]
		//比较数据类型分类是否一致
		if !strings.EqualFold(source.Type, dest.Type) {
			modify = append(modify, u)
			continue
		}
		switch source.Type {
		case "bit":
			if !strings.EqualFold(source.GroupType, dest.GroupType) {
				modify = append(modify, u)
			}
		case "int":
			if !strings.EqualFold(source.Format, dest.Format) {
				modify = append(modify, u)
				continue
			}
			if source.DataLength != dest.DataLength {
				modify = append(modify, u)
			}
		case "float", "double":
			if !strings.EqualFold(source.Format, dest.Format) {
				modify = append(modify, u)
				continue
			}
			a := fmt.Sprintf("%v", reflect.TypeOf(source.ShowSize))
			b := fmt.Sprintf("%v", reflect.TypeOf(dest.ShowSize))
			if !strings.EqualFold(a, b) {
				modify = append(modify, u)
				continue
			}
			if source.DataLength != dest.DataLength {
				modify = append(modify, u)
				continue
			}
			switch strings.ToLower(a) {
			case "int":
				if source.ShowSize.(int) != dest.ShowSize.(int) {
					modify = append(modify, u)
				}
			case "string":
				if !strings.EqualFold(source.ShowSize.(string), dest.ShowSize.(string)) {
					modify = append(modify, u)
				}
			}
		case "decimal":
			st, dt := fmt.Sprintf("%v", reflect.TypeOf(source.ShowSize)), fmt.Sprintf("%v", reflect.TypeOf(dest.ShowSize))
			if strings.EqualFold(st, dt) && strings.EqualFold(st, "int") {
				if source.ShowSize.(int) != dest.ShowSize.(int) {
					modify = append(modify, u)
				}
			} else if strings.EqualFold(st, dt) && strings.EqualFold(st, "string") {
				if !strings.EqualFold(source.ShowSize.(string), dest.ShowSize.(string)) {
					modify = append(modify, u)
				}
			}
		case "time", "timestamp":
			if !strings.EqualFold(source.Format, dest.Format) {
				modify = append(modify, u)
			}
		case "char", "varchar":
			if source.ShowSize.(int) != dest.ShowSize.(int) {
				modify = append(modify, u)
			}
		case "text", "lob":
			if dest.DataLength < source.DataLength {
				modify = append(modify, u)
			}
		}
	}
	return modify
}
func (sp *SchedulePlan2) TableColumnNull(eq []string, s, d any) any {
	var (
		union  []map[string]string
		modify []string
	)
	for _, v := range []any{s, d} {
		switch fmt.Sprintf("%v", reflect.TypeOf(v)) {
		case "[]global.TableMeta":
			var x = make(map[string]string)
			for _, w := range v.([]global.TableMeta) {
				var columnName = w.ColumnName
				if !GlobalPConfigs.rules.Struct.Case {
					columnName = strings.ToUpper(w.ColumnName)
				}
				x[columnName] = w.IsNull
			}
			union = append(union, x)
		}
	}
	for _, u := range eq {
		var columnCover []string
		for _, v := range union {
			if w, ok := v[u]; ok {
				columnCover = append(columnCover, w)
			}
		}
		source, dest := columnCover[0], columnCover[1]
		if !strings.EqualFold(source, dest) {
			modify = append(modify, u)
		}
	}
	return modify
}

func (sp *SchedulePlan2) TableColumnDefault(eq []string, s, d any) any {
	var (
		union  []map[string]global.ConvertDefaultValue
		modify []string
	)
	for _, v := range []any{s, d} {
		switch fmt.Sprintf("%v", reflect.TypeOf(v)) {
		case "[]global.TableMeta":
			var x = make(map[string]global.ConvertDefaultValue)
			for _, w := range v.([]global.TableMeta) {
				var columnName = w.ColumnName
				if !GlobalPConfigs.rules.Struct.Case {
					columnName = strings.ToUpper(w.ColumnName)
				}
				x[columnName] = w.ConvertDefaultValue
			}
			union = append(union, x)
		}
	}
	for _, u := range eq {
		var columnCover []global.ConvertDefaultValue
		for _, v := range union {
			if w, ok := v[u]; ok {
				columnCover = append(columnCover, w)
			}
		}
		source, dest := columnCover[0], columnCover[1]
		if !strings.EqualFold(source.Format, dest.Format) && len(source.Format) > 0 {
			modify = append(modify, u)
		} else if strings.EqualFold(source.Format, dest.Format) && len(source.Format) == 0 {
			if !strings.EqualFold(source.NewValue, dest.NewValue) {
				modify = append(modify, u)
			}
		}
	}
	return modify
}
func (sp *SchedulePlan2) TableColumnComment(eq []string, s, d any) any {
	var (
		union  []map[string]string
		modify []string
	)
	for _, v := range []any{s, d} {
		switch fmt.Sprintf("%v", reflect.TypeOf(v)) {
		case "[]global.TableMeta":
			var x = make(map[string]string)
			for _, w := range v.([]global.TableMeta) {
				var columnName = w.ColumnName
				if !GlobalPConfigs.rules.Struct.Case {
					columnName = strings.ToUpper(w.ColumnName)
				}
				x[columnName] = w.ColumnComment
			}
			union = append(union, x)
		}
	}
	for _, u := range eq {
		var columnCover []string
		for _, v := range union {
			if w, ok := v[u]; ok {
				columnCover = append(columnCover, w)
			}
		}
		source, dest := columnCover[0], columnCover[1]
		if !strings.EqualFold(source, dest) {
			modify = append(modify, u)
		}
	}
	return modify
}
func (sp *SchedulePlan2) TableColumnCharset(eq []string, s, d any) any {
	var (
		union  []map[string]string
		modify []string
	)
	for _, v := range []any{s, d} {
		switch fmt.Sprintf("%v", reflect.TypeOf(v)) {
		case "[]global.TableMeta":
			var x = make(map[string]string)
			for _, w := range v.([]global.TableMeta) {
				var columnName = w.ColumnName
				if !GlobalPConfigs.rules.Struct.Case {
					columnName = strings.ToUpper(w.ColumnName)
				}
				x[columnName] = w.Charset
			}
			union = append(union, x)
		}
	}
	for _, u := range eq {
		var columnCover []string
		for _, v := range union {
			if w, ok := v[u]; ok {
				columnCover = append(columnCover, w)
			}
		}
		source, dest := columnCover[0], columnCover[1]
		if !strings.EqualFold(source, dest) {
			modify = append(modify, u)
		}
	}
	return modify
}
func (sp *SchedulePlan2) TableColumnCollation(eq []string, s, d any) any {
	var (
		union  []map[string]string
		modify []string
	)
	for _, v := range []any{s, d} {
		switch fmt.Sprintf("%v", reflect.TypeOf(v)) {
		case "[]global.TableMeta":
			var x = make(map[string]string)
			for _, w := range v.([]global.TableMeta) {
				var columnName = w.ColumnName
				if !GlobalPConfigs.rules.Struct.Case {
					columnName = strings.ToUpper(w.ColumnName)
				}
				x[columnName] = w.CollationName
			}
			union = append(union, x)
		}
	}
	for _, u := range eq {
		var columnCover []string
		for _, v := range union {
			if w, ok := v[u]; ok {
				columnCover = append(columnCover, w)
			}
		}
		source, dest := columnCover[0], columnCover[1]
		if !strings.EqualFold(source, dest) {
			modify = append(modify, u)
		}
	}
	return modify
}

func (sp *SchedulePlan2) columnAbInfo(b, c string, d, e any) string {
	var (
		m = make(map[string]global.TableMeta)
	)
	emptyIf := func(a string) string {
		if len(a) == 0 {
			return "empty"
		}
		return a
	}
	for k, v := range map[string]any{
		"source": d,
		"dest":   e,
	} {
		switch fmt.Sprintf("%v", reflect.TypeOf(v)) {
		case "[]global.TableMeta":
			if v != nil {
				for _, w := range v.([]global.TableMeta) {
					if strings.EqualFold(c, w.ColumnName) {
						m[k] = w
					}
				}
			}
		}
	}
	switch b {
	case "add":
		if x, ok := m["source"]; ok {
			return fmt.Sprintf(" ### add column [%s] type Value: {source:%s} null Value: {source:%s} charset Value: {source:%s} collation Value: {source:%s} default Value: {source:%s} comment Value: {source:%s}",
				c, emptyIf(x.ColumnType), emptyIf(x.IsNull), emptyIf(x.Charset), emptyIf(x.CollationName), emptyIf(x.ColumnDefault), emptyIf(x.ColumnComment))
		}
	case "drop":
		if x, ok := m["dest"]; ok {
			return fmt.Sprintf(" ### drop column [%s] type Value: {dest:%s} null Value: {dest:%s} charset Value: {dest:%s} collation Value: {dest:%s} default Value: {dest:%s} comment Value: {dest:%s}",
				c, emptyIf(x.ColumnType), emptyIf(x.IsNull), emptyIf(x.Charset), emptyIf(x.CollationName), emptyIf(x.ColumnDefault), emptyIf(x.ColumnComment))
		}
	case "modify":
		x, ok := m["source"]
		y, ok1 := m["dest"]
		if ok && ok1 {
			return fmt.Sprintf(" ### modify column [%s] type Value: {source:%s,dest:%s} null Value: {source:%s,dest:%s} charset Value: {source:%s,dest:%s} collation Value: {source:%s,dest:%s} default Value: {source:%s,dest:%s} comment Value: {source:%s,dest:%s}",
				c, emptyIf(x.ColumnType), emptyIf(y.ColumnType), emptyIf(x.IsNull), emptyIf(y.IsNull), emptyIf(x.Charset), emptyIf(y.Charset), emptyIf(x.CollationName), emptyIf(y.CollationName), emptyIf(x.ColumnDefault), emptyIf(y.ColumnDefault), emptyIf(x.ColumnComment), emptyIf(y.ColumnComment))
		}
	}
	return ""
}
func (sp *SchedulePlan2) indexAbInfo(b, c string, d, e any) string {
	var (
		m = make(map[string]global.IndexMerge)
	)
	emptyIf := func(a string) string {
		if len(a) == 0 {
			return "empty"
		}
		return a
	}
	for k, v := range map[string]any{
		"source": d,
		"dest":   e,
	} {
		switch fmt.Sprintf("%v", reflect.TypeOf(v)) {
		case "global.IndexMerge":
			if v != nil {
				m[k] = v.(global.IndexMerge)
			}
		}
	}
	switch b {
	case "add":
		if x, ok := m["source"]; ok {
			var l []string
			for _, v := range x.IndexColumn[c] {
				l = append(l, v.ColumnName)
			}
			return fmt.Sprintf(" ### add index [%s] type Value: {source:%s} index column Value: {source:%s}",
				c, emptyIf(x.IndexType[c]), emptyIf(strings.Join(l, ",")))
		}
	case "drop":
		if x, ok := m["dest"]; ok {
			var l []string
			for _, v := range x.IndexColumn[c] {
				l = append(l, v.ColumnName)
			}
			return fmt.Sprintf(" ### drop index [%s] type Value: {dest:%s} index column Value: {dest:%s}",
				c, emptyIf(x.IndexType[c]), emptyIf(strings.Join(l, ",")))
		}
	case "modify":
		x, ok := m["source"]
		y, ok1 := m["dest"]
		if ok && ok1 {
			var l, n []string
			for _, v := range x.IndexColumn[c] {
				l = append(l, v.ColumnName)
			}
			for _, v := range y.IndexColumn[c] {
				n = append(n, v.ColumnName)
			}
			return fmt.Sprintf(" ### modify index [%s] type Value: {source:%s,dest:%s} index column Value: {source:%s,dest:%s} index column seq Value: {source:%s,dest:%s}",
				c, emptyIf(x.IndexType[c]), emptyIf(y.IndexType[c]), emptyIf(strings.Join(l, ",")), emptyIf(strings.Join(n, ",")), emptyIf(strings.Join(x.IndexColumnSeq[c], ",")), emptyIf(strings.Join(y.IndexColumnSeq[c], ",")))
		}
	}
	return ""
}
func (sp *SchedulePlan2) partitionAbInfo(b, c string, d, e any) string {
	var (
		m = make(map[string]map[string]global.TablePartitionConfig)
	)
	emptyIf := func(a string) string {
		if len(a) == 0 {
			return "empty"
		}
		return a
	}
	for k, v := range map[string]any{
		"source": d,
		"dest":   e,
	} {
		switch fmt.Sprintf("%v", reflect.TypeOf(v)) {
		case "[]global.TablePartitionConfig":
			var l = make(map[string]global.TablePartitionConfig)
			for _, y := range v.([]global.TablePartitionConfig) {
				l[y.FirstPartition.Name] = y
			}
			m[k] = l
		}
	}
	switch b {
	case "add":
		if x, ok := m["source"]; ok {
			var l global.TablePartitionConfig
			if y, z := x[c]; z {
				l = y
			}
			return fmt.Sprintf(" ### add partition [%v] partition column: {source:%v} partition column meth: {source:%v} partition rules Value: {source:%s}",
				c, emptyIf(strings.Join(l.FirstPartition.ColumnName, ",")), emptyIf(l.FirstPartition.Meth), emptyIf(l.FirstPartition.Rules))
		}
	case "drop":
		if x, ok := m["dest"]; ok {
			var l global.TablePartitionConfig
			if y, z := x[c]; z {
				l = y
			}
			return fmt.Sprintf(" ### drop partition [%s] partition column: {dest:%v} partition column meth: {dest:%v} partition rules Value: {dest:%s}",
				c, emptyIf(strings.Join(l.FirstPartition.ColumnName, ",")), emptyIf(l.FirstPartition.Meth), emptyIf(l.FirstPartition.Rules))
		}
	case "modify":
		x, ok := m["source"]
		y, ok1 := m["dest"]
		if ok && ok1 {
			var l, n global.TablePartitionConfig
			if q, z := x[c]; z {
				l = q
			}
			if q, z := y[c]; z {
				n = q
			}
			return fmt.Sprintf(" ### modify partition [%s] partition column: {source:%v dest:%v} partition column meth: {source:%v dest:%v} partition rules Value: {source:%v dest:%s}",
				c, emptyIf(strings.Join(l.FirstPartition.ColumnName, ",")), emptyIf(strings.Join(n.FirstPartition.ColumnName, ",")), emptyIf(l.FirstPartition.Meth), emptyIf(n.FirstPartition.Meth), emptyIf(l.FirstPartition.Rules), emptyIf(n.FirstPartition.Rules))
		}
	}
	return ""
}
func getSwitchSheet(Behavior, IssueType, Active, Logo, SrcValue, DstValue, FixRecommendation string) outPut.StructSwitchSheet {
	return outPut.StructSwitchSheet{
		Behavior:          Behavior,
		IssueType:         IssueType,
		Active:            Active,
		Logo:              Logo,
		SrcValue:          SrcValue,
		DstValue:          DstValue,
		FixRecommendation: FixRecommendation,
	}
}
func getResultSheet(Behavior, FixFay, Exec, ErrInfo, FixSql, RawSql string) outPut.StructResultSheet {
	return outPut.StructResultSheet{
		Behavior: Behavior,
		FixFay:   FixFay,
		Exec:     Exec,
		ErrInfo:  ErrInfo,
		FixSql:   FixSql,
		RawSql:   RawSql,
	}
}
func (sp *SchedulePlan2) columnDrop(s []string, c, d any, logSeq int64) []FixSqlResult {
	var (
		event    = "[columnDrop]"
		result   []FixSqlResult
		fs       any
		alterSql global.AlterSqlResult
		o        Er.TableColumnEr
		err      error
	)
	if o, err = Er.ColumnData(Er.TableColumn{
		DBType: GlobalPConfigs.dSns.DestDBName,
	}); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("%v Get the table wildcard %v under the specified schema %v failed. error is %v", event, sp.Object.Table, sp.Object.Schema, err))
		return nil
	}
	for _, v := range s {
		var abnormalInfo string
		abnormalInfo = sp.columnAbInfo("drop", v, c, d)
		if fs, err = o.DropColumnSql(global.GetColumnTypeInput{
			LogSeq: logSeq,
			TableInfo: global.TableInfo{
				Schema: sp.Object.MSchema,
				Table:  sp.Object.MTable,
			},
			DdlColumn: global.DdlColumn{
				Name: v,
			}}); err != nil {
			return nil
		} else {
			alterSql = fs.(global.AlterSqlResult)
		}
		if len(alterSql.Sql) == 0 {
			continue
		}
		result = append(result, FixSqlResult{Sql: alterSql.Sql, AbInfo: abnormalInfo})
		sp.XlsSwitch.Data.Struct = getSwitchSheet("alter", "column Name", "drop", v, "''", v, alterSql.Record)
		sp.XlsSwitch.Data.Comment = alterSql.Sql
		newCell.Write(*sp.XlsSwitch)
	}
	return result
}
func (sp *SchedulePlan2) indexDrop(s []string, c, d any, logSeq int64) []FixSqlResult {
	var (
		result   []FixSqlResult
		event    = "[indexDrop]"
		alterSql global.AlterSqlResult
		fs       any
		o        Er.TablesMetaInfoEr
		err      error
	)
	if o, err = Er.MetaInfo(Er.TableInfoMeta{
		DBType: GlobalPConfigs.dSns.DestDBName,
	}); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("%v Get the table wildcard %v under the specified schema %v failed. error is %v", event, sp.Object.Table, sp.Object.Schema, err))
		return nil
	}
	//p := tableEr.MetaInfo(tableEr.TableInfoMeta{DBType: GlobalPConfigs.dSns.DestDBName})
	for _, v := range s {
		var abnormalInfo string
		abnormalInfo = sp.indexAbInfo("drop", v, c, d)
		if fs, err = o.DropIndexSql(global.TablesMetaInfoInput{
			LogSeq: logSeq,
			TableInfo: global.TableInfo{
				Schema: sp.Object.MSchema,
				Table:  sp.Object.MTable,
			},
			IndexMetaGather: global.IndexMetaGather{
				Dst: global.IndexMetaInfo{
					Name:        v,
					Type:        d.(global.IndexMerge).IndexType[v],
					IndexColumn: d.(global.IndexMerge).IndexColumn[v],
				},
			},
		}); err != nil {
			return nil
		} else {
			if fs != nil {
				alterSql = fs.(global.AlterSqlResult)
			}
		}
		if len(alterSql.Sql) == 0 {
			continue
		}
		result = append(result, FixSqlResult{Sql: alterSql.Sql, AbInfo: abnormalInfo})
		sp.XlsSwitch.Data.Struct = getSwitchSheet("alter", fmt.Sprintf("index %v", d.(global.IndexMerge).IndexType[v]), "drop", v, "''", v, alterSql.Record)
		sp.XlsSwitch.Data.Comment = alterSql.Sql
		newCell.Write(*sp.XlsSwitch)
	}
	return result
}
func (sp *SchedulePlan2) partitionDrop(s []string, c, d any, logSeq int64) []FixSqlResult {
	var (
		event    = "[partitionDrop]"
		result   []FixSqlResult
		alterSql global.AlterSqlResult
		o        Er.TablesMetaInfoEr
		fs       any
		err      error
	)
	if o, err = Er.MetaInfo(Er.TableInfoMeta{
		DBType: GlobalPConfigs.dSns.DestDBName,
	}); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("%v Get the table wildcard %v under the specified schema %v failed. error is %v", event, sp.Object.Table, sp.Object.Schema, err))
		return nil
	}
	//p := tableEr.MetaInfo(tableEr.TableInfoMeta{DBType: GlobalPConfigs.dSns.DestDBName})
	for _, v := range s {
		var m = make(map[string]map[string]global.SubPartitionMeta)
		for k, w := range map[string]any{
			"source": c,
			"dest":   d,
		} {
			switch fmt.Sprintf("%v", reflect.TypeOf(w)) {
			case "[]global.TablePartitionConfig":
				if w != nil {
					var e = make(map[string]global.SubPartitionMeta)
					for _, b := range w.([]global.TablePartitionConfig) {
						if strings.EqualFold(b.FirstPartition.Name, v) {
							e[b.FirstPartition.Name] = b.FirstPartition
						}
					}
					m[k] = e
				}
			}
		}
		var abnormalInfo string
		abnormalInfo = sp.partitionAbInfo("drop", v, c, d)
		if fs, err = o.DropPartitionSql(global.TablesMetaInfoInput{
			LogSeq: logSeq,
			TableInfo: global.TableInfo{
				Schema: sp.Object.MSchema,
				Table:  sp.Object.MTable,
			},
			PartitionMetaGarth: global.PartitionMetaGather{
				DstMeta: m["dest"],
			},
		}); err != nil || fs != nil {
			return nil
		} else {
			alterSql = fs.(global.AlterSqlResult)
		}
		if len(alterSql.Sql) == 0 {
			continue
		}
		result = append(result, FixSqlResult{Sql: alterSql.Sql, AbInfo: abnormalInfo})
		sp.XlsSwitch.Data.Struct = getSwitchSheet("alter", "partition name", "drop", v, "''", v, alterSql.Record)
		sp.XlsSwitch.Data.Comment = alterSql.Sql
		newCell.Write(*sp.XlsSwitch)
	}
	return result
}
func (sp *SchedulePlan2) columnAdd(s []string, c, d any, logSeq int64) []FixSqlResult {
	var (
		event    = "[columnAdd]"
		result   []FixSqlResult
		alterSql global.AlterSqlResult
		p        Er.TableColumnEr
		err      error
	)
	if p, err = Er.ColumnData(Er.TableColumn{
		DBType: GlobalPConfigs.dSns.DestDBName,
	}); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("%v Get the table wildcard %v under the specified schema %v failed. error is %v", event, sp.Object.Table, sp.Object.Schema, err))
		return nil
	}
	//p := tableEr.ColumnData(tableEr.TableColumn{DBType: GlobalPConfigs.dSns.DestDBName})
	for _, v := range s {
		var abnormalInfo string
		abnormalInfo = sp.columnAbInfo("add", v, c, d)
		var meta global.TableMeta
		switch fmt.Sprintf("%v", reflect.TypeOf(c)) {
		case "[]global.TableMeta":
			for _, w := range c.([]global.TableMeta) {
				if strings.EqualFold(v, w.ColumnName) {
					meta = w
				}
			}
		}
		if fs, err := p.AddColumnSql(global.GetColumnTypeInput{
			LogSeq: logSeq,
			//DB:     GlobalPConfigs.DDB,
			TableInfo: global.TableInfo{
				Schema: sp.Object.MSchema,
				Table:  sp.Object.MTable,
			},
			DdlColumn: global.DdlColumn{
				Name:  v,
				SMeta: meta,
			}}); err != nil {
			return nil
		} else {
			alterSql = fs.(global.AlterSqlResult)
		}
		if len(alterSql.Sql) == 0 {
			continue
		}
		result = append(result, FixSqlResult{Sql: alterSql.Sql, AbInfo: abnormalInfo})
		sp.XlsSwitch.Data.Struct = getSwitchSheet("alter", "column name", "add", v, meta.ColumnType, "''", alterSql.Record)
		sp.XlsSwitch.Data.Comment = alterSql.Sql
		newCell.Write(*sp.XlsSwitch)
	}
	return result
}

func (sp *SchedulePlan2) indexAdd(s []string, c, d any, partGather []string, logSeq int64) []FixSqlResult {
	var (
		event    = "[indexAdd]"
		result   []FixSqlResult
		alterSql global.AlterSqlResult
		fs       any
		o        Er.TablesMetaInfoEr
		err      error
	)
	if o, err = Er.MetaInfo(Er.TableInfoMeta{
		DBType: GlobalPConfigs.dSns.DestDBName,
	}); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("%v Get the table wildcard %v under the specified schema %v failed. error is %v", event, sp.Object.Table, sp.Object.Schema, err))
		return nil
	}
	//p := tableEr.MetaInfo(tableEr.TableInfoMeta{DBType: GlobalPConfigs.dSns.DestDBName})
	for _, v := range s {
		var abnormalInfo string
		abnormalInfo = sp.indexAbInfo("add", v, c, d)
		if fs, err = o.AddIndexSql(global.TablesMetaInfoInput{
			LogSeq: logSeq,
			TableInfo: global.TableInfo{
				Schema: sp.Object.MSchema,
				Table:  sp.Object.MTable,
			},
			IndexMetaGather: global.IndexMetaGather{
				Src: global.IndexMetaInfo{
					Name:        v,
					Type:        c.(global.IndexMerge).IndexType[v],
					IndexColumn: c.(global.IndexMerge).IndexColumn[v],
				},
				PartColumn: partGather,
			},
		}); err != nil {
			return nil
		} else {
			if fs != nil {
				alterSql = fs.(global.AlterSqlResult)
			}
		}
		if len(alterSql.Sql) == 0 {
			continue
		}

		result = append(result, FixSqlResult{Sql: alterSql.Sql, AbInfo: abnormalInfo})
		sp.XlsSwitch.Data.Struct = getSwitchSheet("alter", fmt.Sprintf("index %v", d.(global.IndexMerge).IndexType[v]), "add", v, v, "''", alterSql.Record)
		sp.XlsSwitch.Data.Comment = alterSql.Sql
		newCell.Write(*sp.XlsSwitch)
	}
	return result
}
func (sp *SchedulePlan2) partitionAdd(s []string, c, d any, logSeq int64) []FixSqlResult {
	var (
		event    = "[partitionAdd]"
		result   []FixSqlResult
		fs       any
		alterSql global.AlterSqlResult
		o        Er.TablesMetaInfoEr
		err      error
	)
	if o, err = Er.MetaInfo(Er.TableInfoMeta{
		DBType: GlobalPConfigs.dSns.DestDBName,
	}); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("%v Get the table wildcard %v under the specified schema %v failed. error is %v", event, sp.Object.Table, sp.Object.Schema, err))
		return nil
	}
	//p := tableEr.MetaInfo(tableEr.TableInfoMeta{DBType: GlobalPConfigs.dSns.DestDBName})
	for _, v := range s {
		var m = make(map[string]map[string]global.SubPartitionMeta)
		for k, w := range map[string]any{
			"source": c,
			"dest":   d,
		} {
			switch fmt.Sprintf("%v", reflect.TypeOf(w)) {
			case "[]global.TablePartitionConfig":
				if w != nil {
					var e = make(map[string]global.SubPartitionMeta)
					for _, b := range w.([]global.TablePartitionConfig) {
						if strings.EqualFold(b.FirstPartition.Name, v) {
							e[b.FirstPartition.Name] = b.FirstPartition
						}
					}
					m[k] = e
				}
			}
		}
		var abnormalInfo string
		abnormalInfo = sp.partitionAbInfo("add", v, c, d)
		if fs, err = o.AddPartitionSql(global.TablesMetaInfoInput{
			LogSeq: logSeq,
			TableInfo: global.TableInfo{
				Schema: sp.Object.MSchema,
				Table:  sp.Object.MTable,
			},
			PartitionMetaGarth: global.PartitionMetaGather{
				SrcMeta: m["source"],
			},
		}); err != nil || fs != nil {
			return nil
		} else {
			alterSql = fs.(global.AlterSqlResult)
		}
		if len(alterSql.Sql) == 0 {
			continue
		}
		result = append(result, FixSqlResult{Sql: alterSql.Sql, AbInfo: abnormalInfo})
		sp.XlsSwitch.Data.Struct = getSwitchSheet("alter", "partition name", "add", v, v, "''", alterSql.Record)
		sp.XlsSwitch.Data.Comment = alterSql.Sql
		newCell.Write(*sp.XlsSwitch)
	}
	return result
}
func (sp *SchedulePlan2) issueXls(z *global.MetaAttributesAb, m map[string]global.TableMeta) (issue, src, dst string) {
	var srcValue, dstValue []string
	if z.Type {
		issue = fmt.Sprintf("type %v", m["source"].ConvertColumnType.Type)
		srcValue = append(srcValue, fmt.Sprintf("type: %v", m["source"].ColumnType))
		dstValue = append(dstValue, fmt.Sprintf("type: %v", m["dest"].ColumnType))
	}
	if z.Null {
		issue = "column null"
		srcValue = append(srcValue, fmt.Sprintf("null: %v", m["source"].IsNull))
		dstValue = append(dstValue, fmt.Sprintf("null: %v", m["dest"].IsNull))
	}
	if z.Default {
		issue = "column default"
		srcValue = append(srcValue, fmt.Sprintf("default: %v", m["source"].ColumnDefault))
		dstValue = append(dstValue, fmt.Sprintf("default: %v", m["dest"].ColumnDefault))
	}
	if z.Comment {
		issue = "column comment"
		srcValue = append(srcValue, fmt.Sprintf("comment: %v", m["source"].ColumnComment))
		dstValue = append(dstValue, fmt.Sprintf("comment: %v", m["dest"].ColumnComment))
	}
	if z.Charset {
		issue = "column charset"
		srcValue = append(srcValue, fmt.Sprintf("charset: %v", m["source"].Charset))
		dstValue = append(dstValue, fmt.Sprintf("charset: %v", m["dest"].Charset))
	}
	if z.Collation {
		issue = "column collation"
		srcValue = append(srcValue, fmt.Sprintf("collation: %v", m["source"].CollationName))
		dstValue = append(dstValue, fmt.Sprintf("collation: %v", m["dest"].CollationName))
	}
	return issue, strings.Join(srcValue, "\n"), strings.Join(dstValue, "\n")
}

// 处理modify column 信息
func (sp *SchedulePlan2) columnModify(s map[string]*global.MetaAttributesAb, c, d any, partGather, priGather []string, logSeq int64) []FixSqlResult {
	var (
		event    = "[columnModify]"
		result   []FixSqlResult
		fs       any
		alterSql global.AlterSqlResult
		o        Er.TableColumnEr
		err      error
	)
	if o, err = Er.ColumnData(Er.TableColumn{
		DBType: GlobalPConfigs.dSns.DestDBName,
	}); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("%v Get the table wildcard %v under the specified schema %v failed. error is %v", event, sp.Object.Table, sp.Object.Schema, err))
		return nil
	}
	//处理modify column
	//p := tableEr.ColumnData(tableEr.TableColumn{DBType: GlobalPConfigs.dSns.DestDBName})
	for v, z := range s {
		var m = make(map[string]global.TableMeta)
		for k, w := range map[string]any{
			"source": c,
			"dest":   d,
		} {
			switch fmt.Sprintf("%v", reflect.TypeOf(w)) {
			case "[]global.TableMeta":
				if w != nil {
					for _, x := range w.([]global.TableMeta) {
						if strings.EqualFold(v, x.ColumnName) {
							m[k] = x
						}
					}
				}
			}
		}
		if jsonStr, err := json.Marshal(*z); err != nil {
			return nil
		} else {
			if !strings.Contains(string(jsonStr), "true") {
				continue
			}
		}
		var abnormalInfo string
		abnormalInfo = sp.columnAbInfo("modify", v, c, d)
		if fs, err = o.ModifyColumnSql(global.GetColumnTypeInput{
			LogSeq: logSeq,
			TableInfo: global.TableInfo{
				Schema: sp.Object.MSchema,
				Table:  sp.Object.MTable,
			},
			DdlColumn: global.DdlColumn{
				Name:       v,
				SMeta:      m["source"],
				DMeta:      m["dest"],
				PriColumn:  priGather,
				PartColumn: partGather,
				Attributes: z,
			}}); err != nil {
			return nil
		} else {
			alterSql = fs.(global.AlterSqlResult)
		}
		if len(alterSql.Sql) == 0 {
			continue
		}
		result = append(result, FixSqlResult{Sql: alterSql.Sql, AbInfo: abnormalInfo})
		issue, srcVal, dstVal := sp.issueXls(z, m)
		sp.XlsSwitch.Data.Struct = getSwitchSheet("alter", issue, "modify", v, srcVal, dstVal, alterSql.Record)
		sp.XlsSwitch.Data.Comment = alterSql.Sql
		newCell.Write(*sp.XlsSwitch)
	}
	return result
}

// 处理modify column 信息
func (sp *SchedulePlan2) indexModify(s map[string]*global.IndexAttributesAb, c, d any, partGather []string, logSeq int64) []FixSqlResult {
	var (
		event              = "[indexModify]"
		result             []FixSqlResult
		srcValue, dstValue string
		alterSql           global.AlterSqlResult
		fs                 any
		o                  Er.TablesMetaInfoEr
		err                error
	)
	if o, err = Er.MetaInfo(Er.TableInfoMeta{
		DBType: GlobalPConfigs.dSns.DestDBName,
	}); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("%v Get the table wildcard %v under the specified schema %v failed. error is %v", event, sp.Object.Table, sp.Object.Schema, err))
		return nil
	}
	//处理modify column
	//p := tableEr.MetaInfo(tableEr.TableInfoMeta{DBType: GlobalPConfigs.dSns.DestDBName})
	for v, z := range s {
		if !z.Type && !z.ColumnName {
			continue
		}
		var m = make(map[string]global.IndexMerge)
		for k, w := range map[string]any{
			"source": c,
			"dest":   d,
		} {
			switch fmt.Sprintf("%v", reflect.TypeOf(w)) {
			case "global.IndexMerge":
				if w != nil {
					m[k] = w.(global.IndexMerge)
				}
			}
		}
		var abnormalInfo string
		abnormalInfo = sp.indexAbInfo("modify", v, c, d)
		if fs, err = o.ModifyIndexSql(global.TablesMetaInfoInput{
			LogSeq: logSeq,
			TableInfo: global.TableInfo{
				Schema: sp.Object.MSchema,
				Table:  sp.Object.MTable,
			},
			IndexMetaGather: global.IndexMetaGather{
				Src: global.IndexMetaInfo{
					Type:        c.(global.IndexMerge).IndexType[v],
					Name:        v,
					IndexColumn: c.(global.IndexMerge).IndexColumn[v],
				},
				Dst: global.IndexMetaInfo{
					Type:        d.(global.IndexMerge).IndexType[v],
					Name:        v,
					IndexColumn: d.(global.IndexMerge).IndexColumn[v],
				},
				PartColumn: partGather,
			},
		}); err != nil {
			return nil
		} else {
			alterSql = fs.(global.AlterSqlResult)
		}
		if len(alterSql.Sql) == 0 {
			continue
		}
		if z.Type {
			srcValue = c.(global.IndexMerge).IndexType[v]
			dstValue = d.(global.IndexMerge).IndexType[v]
		}
		if z.ColumnName {
			var w, q []string
			for _, g := range c.(global.IndexMerge).IndexColumn[v] {
				w = append(w, g.ColumnName)
			}
			for _, g := range d.(global.IndexMerge).IndexColumn[v] {
				q = append(q, g.ColumnName)
			}
			srcValue = strings.Join(w, ",")
			dstValue = strings.Join(q, ",")
		}
		result = append(result, FixSqlResult{Sql: alterSql.Sql, AbInfo: abnormalInfo})
		sp.XlsSwitch.Data.Struct = getSwitchSheet("alter", fmt.Sprintf("index %v", d.(global.IndexMerge).IndexType[v]), "modify", v, srcValue, dstValue, alterSql.Record)
		sp.XlsSwitch.Data.Comment = alterSql.Sql
		newCell.Write(*sp.XlsSwitch)
	}
	return result
}

// 处理modify column 信息
func (sp *SchedulePlan2) partitionModify(s []string, c, d any, logSeq int64) []FixSqlResult {
	var (
		event    = "[partitionModify]"
		fs       any
		result   []FixSqlResult
		alterSql global.AlterSqlResult
		o        Er.TablesMetaInfoEr
		err      error
	)
	if o, err = Er.MetaInfo(Er.TableInfoMeta{
		DBType: GlobalPConfigs.dSns.DestDBName,
	}); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("%v Get the table wildcard %v under the specified schema %v failed. error is %v", event, sp.Object.Table, sp.Object.Schema, err))
		return nil
	}
	//p := tableEr.MetaInfo(tableEr.TableInfoMeta{DBType: GlobalPConfigs.dSns.DestDBName})
	for _, v := range s {
		var m = make(map[string]map[string]global.SubPartitionMeta)
		for k, w := range map[string]any{
			"source": c,
			"dest":   d,
		} {
			switch fmt.Sprintf("%v", reflect.TypeOf(w)) {
			case "[]global.TablePartitionConfig":
				if w != nil {
					var e = make(map[string]global.SubPartitionMeta)
					for _, b := range w.([]global.TablePartitionConfig) {
						if strings.EqualFold(b.FirstPartition.Name, v) {
							e[b.FirstPartition.Name] = b.FirstPartition
						}
					}
					m[k] = e
				}
			}
		}
		var abnormalInfo string
		abnormalInfo = sp.partitionAbInfo("modify", v, c, d)
		if fs, err = o.ModifyPartitionSql(global.TablesMetaInfoInput{
			LogSeq: logSeq,
			TableInfo: global.TableInfo{
				Schema: sp.Object.MSchema,
				Table:  sp.Object.MTable,
			},
			PartitionMetaGarth: global.PartitionMetaGather{
				SrcMeta: m["source"],
				DstMeta: m["dest"],
			},
		}); err != nil || fs == nil {
			return nil
		} else {
			alterSql = fs.(global.AlterSqlResult)
		}
		if len(alterSql.Sql) == 0 {
			continue
		}
		result = append(result, FixSqlResult{Sql: alterSql.Sql, AbInfo: abnormalInfo})
		sp.XlsSwitch.Data.Struct = getSwitchSheet("alter", "partition name", "modify", v, m["source"][v].Rules, m["dest"][v].Rules, alterSql.Record)
		sp.XlsSwitch.Data.Comment = alterSql.Sql
		newCell.Write(*sp.XlsSwitch)
	}
	return result
}

// alterFixSql 表结构差异修复语句
func (sp *SchedulePlan2) alterFixSql(gtm *global.GetTableMeta, logSeq int64) ([]FixSqlResult, error) {
	var (
		result                []FixSqlResult
		event                 = "[alterFixSql]"
		partGather, priGather []string /*分区列集合，主键列集合*/
	)
	if len(gtm.PartitionMeta) > 0 {
		s, ok1 := gtm.PartitionMeta["source"]
		d, ok2 := gtm.PartitionMeta["dest"]
		if ok2 && len(d) > 0 {
			partGather = d[0].FirstPartition.ColumnName
		}
		if !ok1 && !ok2 {
			err := errors.New(fmt.Sprintf("source and dest table partition data must exist. source column data exist status {%v},dest partition data exist status {%v}", ok1, ok2))
			log.ErrorLog().Error(fmt.Sprintf("(%v) %v %v", logSeq, event, err))
			return nil, err
		}
		result = append(result, sp.partitionDrop(gtm.PartitionAbnormal.Del, s, d, logSeq)...)
		result = append(result, sp.partitionAdd(gtm.PartitionAbnormal.Add, s, d, logSeq)...)
		result = append(result, sp.partitionModify(gtm.PartitionAbnormal.Mod, s, d, logSeq)...)
	}
	if len(gtm.IndexMeta) > 0 {
		s, _ := gtm.IndexMeta["source"]
		d, ok2 := gtm.IndexMeta["dest"]
		if ok2 {
			for k, v := range d.IndexType {
				if strings.EqualFold(v, "pri") {
					for _, y := range d.IndexColumn[k] {
						priGather = append(priGather, y.ColumnName)
					}
				}
			}
		}
		result = append(result, sp.indexDrop(gtm.IndexAbnormal.Del, s, d, logSeq)...)
		result = append(result, sp.indexAdd(gtm.IndexAbnormal.Add, s, d, partGather, logSeq)...)
		result = append(result, sp.indexModify(gtm.IndexAbnormal.Mod, s, d, partGather, logSeq)...)
	}
	if len(gtm.ColumnMeta) > 0 {
		s, ok1 := gtm.ColumnMeta["source"]
		d, ok2 := gtm.ColumnMeta["dest"]
		if !ok1 || !ok2 {
			err := errors.New(fmt.Sprintf("source and dest table column data must exist. source column data exist status {%v},dest column data exist status {%v}", ok1, ok2))
			log.ErrorLog().Error(fmt.Sprintf("(%v) %v %v", logSeq, event, err))
			return nil, err
		}
		result = append(result, sp.columnDrop(gtm.MetaAbnormal.Del, s, d, logSeq)...)
		result = append(result, sp.columnAdd(gtm.MetaAbnormal.Add, s, d, logSeq)...)
		result = append(result, sp.columnModify(gtm.MetaAbnormal.Mod, s, d, partGather, priGather, logSeq)...)
	}

	return result, nil
}
func (sp SchedulePlan2) createAbInfo(gtm *global.GetTableMeta) string {
	var (
		createResult []string
	)
	//打印列属性
	for _, v := range gtm.ColumnMeta["source"] {
		createResult = append(createResult, fmt.Sprintf("seq:%v columnName:%v columnType:%v columnNull:%v columnDefault:%v columnComment:%v", v.ColumnSeq, v.ColumnName, v.ColumnType, v.IsNull, v.ColumnDefault, v.ColumnComment))
	}
	//打印索引属性
	p := gtm.IndexMeta["source"]
	for k, v := range p.IndexColumn {
		var columnGather []string
		var Cardinality string
		for m, l := range v {
			columnGather = append(columnGather, l.ColumnName)
			if m == len(v)-1 {
				Cardinality = l.Cardinality
			}
		}
		createResult = append(createResult, fmt.Sprintf("indexName:%v indexType:%v indexColumn:%v Cardinality:%v", k, p.IndexType[k], strings.Join(columnGather, ","), Cardinality))
	}
	//打印分区规则
	q := gtm.PartitionMeta["source"]
	for _, v := range q {
		var subPartition []string
		for _, m := range v.SubPartMeta {
			subPartition = append(subPartition, fmt.Sprintf("\tseq:%v subPartitionName:%v subPartitionMeth:%v subPartitionFunc:%v subPartitionColumn:%v subPartitionRules:%v", m.Seq, m.Name, m.Meth, strings.Join(m.Func, ","), strings.Join(v.FirstPartition.ColumnName, ","), v.FirstPartition.Rules))
		}
		if len(v.FirstPartition.Meth) > 0 {
			createResult = append(createResult, fmt.Sprintf("seq:%v partitionName:%v partitionMeth:%v partitionFunc:%v partitionColumn:%v partitionRules:%v", v.FirstPartition.Seq, v.FirstPartition.Name, v.FirstPartition.Meth, strings.Join(v.FirstPartition.Func, ","), strings.Join(v.FirstPartition.ColumnName, ","), v.FirstPartition.Rules))
		}
		if len(subPartition) > 0 {
			createResult = append(createResult, subPartition...)
		}
	}
	return strings.Join(createResult, "\n")
}

func execFixSqlInput(plan *SchedulePlan2, sql []string, fn func() outPut.FileOperations) global.TableActiveInput {
	return global.TableActiveInput{
		LogSeq: plan.Object.ObjectLogSeq,
		//DB:        GlobalPConfigs.DDB,
		TableInfo: global.TableInfo{Schema: plan.Object.MSchema, Table: plan.Object.MTable, ShardName: "single"},
		Input:     global.StartPartConfigInputP{SqlLogBin: GlobalPConfigs.structs.SqlLogBin},
		Alter:     global.Alter{Active: GlobalPConfigs.repair.DataFix, SqlGather: sql, FilePoint1: fn()},
	}
}
func execSql(t Er.TableActiveEr, in global.TableActiveInput) (err error) {
	var result any
	var event = "[execSql]"
	var timeOut int64
	if result, err = t.Alter(in); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("(%v) %v Table %v.%v(%v) failed to execute the ddl statement, with the error message is \"%v\", and the sql statement was executed as \"%v\"", in.LogSeq, event, in.TableInfo.Schema, in.TableInfo.Table, in.TableInfo.ShardName, err, in.Alter.SqlGather))
		return
	}
	switch result.(type) {
	case int64:
		timeOut = result.(int64)
	}
	log.MainLog().Info(fmt.Sprintf("(%v) %v Table %v.%v(%v) successful to execute the ddl statement, execution time is %vms", in.LogSeq, event, in.TableInfo.Schema, in.TableInfo.Table, in.TableInfo.ShardName, timeOut))
	log.MainLog().Debug(fmt.Sprintf("(%v) %v Table %v.%v(%v) successful to execute the ddl statement, and the sql statement was executed as \"%v\" execution time is %vms", in.LogSeq, event, in.TableInfo.Schema, in.TableInfo.Table, in.TableInfo.ShardName, in.Alter.SqlGather, timeOut))
	return
}
func fixSqlFileHeadInfo(plan *SchedulePlan2, fs []FixSqlResult) (s []string) {
	s = append(s, fmt.Sprintf("/* \n------schema:`%s` table:`%s` ddl ------\n", plan.Object.MSchema, plan.Object.MTable))
	for _, v := range fs {
		ab := v.AbInfo
		s = append(s, ab)
	}
	s = append(s, fmt.Sprintf("*/\n"))
	return
}
func fixSqlFileBodyInfo(fs []FixSqlResult) (r, s []string) {
	for _, v := range fs {
		s = append(s, v.Sql)
		r = append(r, v.AbInfo)
	}
	return
}
func applySqlFilter(message mq.Message) (Sql map[string]string) {
	var sqlGarth = message.Properties["fixSqlResult"].([]FixSqlResult)
	var plan = message.Properties["plan"].(*SchedulePlan2)
	//var tableMeta = message.Properties["tableMeta"].(*global.GetTableMeta)
	var rSql, eSql []string
	Sql = make(map[string]string)
	switch GlobalPConfigs.repair.DataFix {
	case "table":
		rSql, eSql = fixSqlFileBodyInfo(sqlGarth)
		for k, v := range eSql {
			Sql[rSql[k]] = v
		}
	case "file":
		rSql, eSql = fixSqlFileBodyInfo(sqlGarth)
		for k, v := range eSql {
			Sql[rSql[k]] = fmt.Sprintf("%v %v", strings.Join(fixSqlFileHeadInfo(plan, sqlGarth), "\n"), v)
		}
	}
	return
}

func getBehavior(message mq.Message) string {
	var tableMeta = message.Properties["tableMeta"].(*global.GetTableMeta)
	if tableMeta.AlterStatus {
		return "alter"
	}
	return "create"
}
func getFixFilePoint(message mq.Message) outPut.FileOperations {
	var tableMeta = message.Properties["tableMeta"].(*global.GetTableMeta)
	var plan = message.Properties["plan"].(*SchedulePlan2)
	switch GlobalPConfigs.repair.FixFileWay {
	case "split":
		if tableMeta.AlterStatus {
			return plan.fixFile.AlterFilePoint
		} else {
			return plan.fixFile.CreateFilePoint
		}
	case "many":
		return plan.fixFile.SchemaFilePoint
	}
	return nil
}

// execFixSql 表结构差异修复语句
func (sp *SchedulePlan2) execFixSql(message mq.Message) (err error) {
	var event, execRecord, comment = "[execFixSql]", "success", "执行完成"
	var t Er.TableActiveEr
	if t, err = Er.TActive(Er.TableActive{DBType: GlobalPConfigs.dSns.DestDBName}); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("%v Get the table wildcard %v under the specified schema %v failed. error is %v", event, sp.Object.Table, sp.Object.Schema, err))
		return
	}
	for k, v := range applySqlFilter(message) {
		if err = execSql(t, execFixSqlInput(sp, []string{v}, func() outPut.FileOperations { return getFixFilePoint(message) })); err != nil {
			comment = "执行失败"
			execRecord = "fail"
		}
		sp.XlsResult.Data.Struct = getResultSheet(getBehavior(message), GlobalPConfigs.repair.DataFix, execRecord, fmt.Sprintf("%v", err), v, k)
		sp.XlsResult.Data.Comment = comment
		newCell.Write(*sp.XlsResult)
	}
	return
}
